use sea_orm::{DatabaseConnection, DbErr, EntityTrait, QueryFilter, ColumnTrait, QuerySelect};
use sea_orm::sea_query::{Expr, OnConflict};
use crate::models::rbac::role_menu::ActiveModel;
use crate::models::rbac::role_menu::{Entity, Column};

pub struct RoleMenuService;

impl RoleMenuService {
    pub async fn assign_menu_to_role(
        db: &DatabaseConnection,
        role_id: &str,
        menu_id: &str,
        tenant_id: i64
    ) -> Result<u64, DbErr> {
        let model = Entity::ActiveModel {
            role_id: sea_orm::Set(role_id.to_string()),
            menu_id: sea_orm::Set(menu_id.to_string()),
            tenant_id: sea_orm::Set(tenant_id),
            ..Default::default()
        };

        Entity::insert(model)
            .on_conflict(
                OnConflict::columns([
                    Column::RoleId, 
                    Column::MenuId,
                    Column::TenantId
                ])
                .do_nothing()
                .to_owned()
            )
            .exec(db)
            .await
            .map(|_| 1)
    }

    pub async fn remove_menu_from_role(
        db: &DatabaseConnection,
        role_id: &str,
        menu_id: &str,
        tenant_id: i64
    ) -> Result<u64, DbErr> {
        Entity::delete_many()
            .filter(Column::RoleId.eq(role_id))
            .filter(Column::MenuId.eq(menu_id))
            .filter(Column::TenantId.eq(tenant_id))
            .exec(db)
            .await
            .map(|r| r.rows_affected)
    }

    pub async fn find_menus_by_role(
        db: &DatabaseConnection,
        role_id: &str,
        tenant_id: i64
    ) -> Result<Vec<String>, DbErr> {
        Entity::find()
            .filter(Column::RoleId.eq(role_id))
            .filter(Column::TenantId.eq(tenant_id))
            .select_only()
            .column(Column::MenuId)
            .into_tuple()
            .all(db)
            .await
    }

    pub async fn find_roles_by_menu(
        db: &DatabaseConnection,
        menu_id: &str,
        tenant_id: i64
    ) -> Result<Vec<String>, DbErr> {
        Entity::find()
            .filter(Column::MenuId.eq(menu_id))
            .filter(Column::TenantId.eq(tenant_id))
            .select_only()
            .column(Column::RoleId)
            .into_tuple()
            .all(db)
            .await
    }
}
